#include "head.h"
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/err.h>

// 错误处理函数
void handleErrors(void) {
    ERR_print_errors_fp(stderr);
    abort();
}
//客户端i
bool calculate_file_hash(const char *file_path, unsigned char *hash_out, unsigned int *hash_len) {
    FILE *file = fopen(file_path, "rb");
    if (!file) {
        perror("fopen");
        return false;
    }

    EVP_MD_CTX *mdctx;
    if ((mdctx = EVP_MD_CTX_new()) == NULL) {
        handleErrors();
    }

    if (1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) {
        handleErrors();
    }

    const int buf_size = 32768;
    unsigned char buffer[buf_size];
    int bytes_read = 0;

    while ((bytes_read = fread(buffer, 1, buf_size, file)) > 0) {
        if (1 != EVP_DigestUpdate(mdctx, buffer, bytes_read)) {
            handleErrors();
        }
    }

    if (ferror(file)) {
        perror("fread");
        fclose(file);
        return false;
    }

    if (1 != EVP_DigestFinal_ex(mdctx, hash_out, hash_len)) {
        handleErrors();
    }

    EVP_MD_CTX_free(mdctx);
    fclose(file);
    return true;
}
// 将哈希值转换为十六进制字符串
void hash_to_hex(const unsigned char *hash, char *hex_out) {
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(hex_out + (i * 2), "%02x", hash[i]);
    }
    hex_out[SHA256_DIGEST_LENGTH * 2] = '\0';
}
// 打印哈希值
void print_hash(unsigned char *hash) {
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        printf("%02x", hash[i]);
    }
    printf("\n");
}

char* stdin_read(char* bufs, client_status* user) {
    //删除回车
    int len = strlen(bufs);
    len = len - 1;
    bufs[len] = '\0';
    //解剖 命令 空格切开
    char* savebuf = { 0 };
    char* token = strtok_r(bufs, " ", &savebuf);
    //printf("last :%s\n",savebuf);
    //保存当前路径
    strcpy(user->path, "/");
    //保存 后续切割路径
    strcpy(user->path_last, savebuf);

    return token;
}
bool get_filename(char* file_name, char* path, char path_cur[1000]) {
    // char path[] = "trgl/network-disk-simulation/my_project/serve";
    char* last_slash = strrchr(path_cur, '/');

    if (last_slash != NULL) {
        // 提取文件名
        strcpy(file_name, last_slash + 1);
        // file_name = last_slash + 1;

        // 提取前面的路径
        size_t path_len = last_slash - path_cur;
        // char dir_path[100];  // 确保这个大小足够存储路径
        strncpy(path, path_cur, path_len);
        path[path_len] = '\0';  // 确保字符串终止

        printf("文件名: %s\n", file_name);
        printf("路径: %s\n", path);
    }
    else {
        strcpy(file_name, path_cur);
    //    path[0] = '\0';
        // 没有找到斜杠，整个路径就是文件名
        printf("文件名: %s\n", file_name);
        printf("路径为空\n");
    }
    return true;

}

bool my_puts(sendMsg msg, client_status clients,int socket_fd){

    strcat(msg.msg,clients.path);
    //printf("path1:%s\n",msg.msg);
//  strcat(msg.msg,clients.path_last);

  //  printf("path:%s\n",msg.msg);
    msg.mode=3;
  //  send(socket_fd,&msg,sizeof(msg),MSG_NOSIGNAL);
    //获取文件名
    char path_now[1000];
    strcpy(path_now,clients.path_last);
    printf("path_last:%s\n",clients.path_last);
    char file_name[256];
    bzero(file_name,sizeof(file_name));
    char path[100];
    bzero(path,sizeof(path));
 //   char * result = strchr(path_now, '/');
    get_filename(file_name,path,path_now);
    strcat(msg.msg,path);
    //计算哈希
    
    //printf("file_name:%s\n",msg.file_name);
    strcpy(msg.file_name,file_name);
   //  send(socket_fd,&msg,sizeof(msg),MSG_NOSIGNAL);
    //2、要上传的路径
    // 计算并打印文件哈希值
    unsigned char hash[SHA256_DIGEST_LENGTH];
    unsigned int hash_len;
    if (calculate_file_hash(file_name, hash, &hash_len) == false) {
        printf("文件打开失败\n");
        return false;
    }
    print_hash(hash);
    char hex_hash[64]={0};
    hash_to_hex(hash, hex_hash);
    //printf("hash:%s\n",hex_hash);
    memcpy(msg.hash_values,hex_hash,sizeof(hex_hash));
    //printf("file_name:%s\n",msg.file_name);
    //sleep(20);
    send(socket_fd,&msg,sizeof(msg),0);
    //printf("-------\n");
    
    printf("mag:\n");
    recvMsg msg1;//服务端发送的状态信息及偏移量信息
    recv(socket_fd,&msg1,sizeof(msg1),MSG_WAITALL);
    printf("mag:%s,statu:%s\n",msg1.msg,msg1.statu);

    if(strcmp("echo",msg1.statu)==0){
        printf("本地已有该文件，无需重复上传！\n");
        return true;
    }
    if(strcmp("fast",msg1.statu)==0){
        printf("极速秒传成功！\n");
        return true;
    }
   // if(strcmp("endless",msg1.statu)==0){
     //   printf("进行断点重传！\n");
   // }
    
    //包括断点重传和第一次上传
    printf("正在进行文件上传！\n");

    //进行正常传输逻辑
    off_t received_size=atoi(msg1.msg);//文件偏移量
    printf("off_set:%ld\n",received_size);


    int file_fd = open(file_name, O_RDWR);
    // ERROR_CHECK(file_fd,-1,"file_fd");

    if(file_fd==-1){
        printf("错误路径,本地找不到文件，请重新输入\n");
        return false;
    }

    struct stat st;
    fstat(file_fd, &st);
    int ret_send =send(socket_fd, &st.st_size, sizeof(off_t), MSG_NOSIGNAL);

    ERROR_CHECK(ret_send,-1,"ret_send");

    //如果 偏移量是和文件大小一样就退出 并且告诉用户已经有
    //还不够健全 应该是核实对方的hash值 才知道是不是已经存在
    off_t offset = received_size;
    ssize_t sent_bytes;
    while (offset < st.st_size) {
        sent_bytes = sendfile(socket_fd, file_fd, &offset, st.st_size - offset);
        if (sent_bytes <= 0) {
            if (errno == EINTR || errno == EAGAIN) {
                continue; // 如果发生了中断或资源临时不可用，继续发送
            } else {
                perror("sendfile");
                close(file_fd);
                return false;
            }
        }
        printf("sent_bytes:%ld\n",sent_bytes);
        offset += sent_bytes;
    }

    // 零拷贝

    close(file_fd);
    return true;

}
